using System.Web.Services;
using System.Web;
using System.Xml;
using System;

using NashuaMobile;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington
	Started:	2004-08-10
	Status:		live
	Version:	1.0.2
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/

namespace umlungu.engineX.workflowX {
	/// <summary>
	/// Identifies how a selection is to be made.
	/// Typically passed to a stored procedure to select a list of records from the database
	/// </summary>
	public enum SelectionIdentifier {
		/// <summary>Select by User identifier</summary>
	    byUser = 1,
		/// <summary>Select by Process identifier</summary>
	    byProcess = 2,
		/// <summary>Select by Agent identifier</summary>
        byAgent = 3,
        /// <summary>Select by (process) Owner identifier</summary>
        byOwner = 4,
        /// <summary>Select by (process) Process type identifier</summary>
        byProcessType = 5,
        /// <summary>Select by (process) Process type category identifier</summary>
        byProcessTypeCategory = 6,
        /// <summary>Select by (process) Process activate type identifier</summary>
        byProcessActivation = 7
	}
	/// <summary>
	/// Identifies a work-state.
	/// Indicates the progress (or lack thereof) within the workflow.
	/// <note>Matches the values held within the State table</note>
	/// </summary>
	public enum WorkStateIdentifier {
		/// <summary>Started</summary> 
	    started = 1,
		/// <summary>In Progress</summary> 
	    progress = 2,
		/// <summary>Completed</summary> 
	    complete = 3,
		/// <summary>On Hold</summary> 
	    onhold = 4,
		/// <summary>Stalled</summary> 
	    stalled = 5,
		/// <summary>Cancelled</summary> 
	    cancelled = 6,
		/// <summary>Intialized</summary> 
	    intialized = 7,
		/// <summary>Waiting (Response)</summary> 
	    waitresponse = 8,
		/// <summary>Waiting (Response)</summary> 
	    waitresponse_2 = 9

	}
	/// <summary>
	/// Identifies a work-status.
	/// Indicates the urgency of the work-item within the workflow.
	/// <note>Matches the values held within the Status table</note>
	/// </summary>
	public enum WorkStatusIdentifier {
		/// <summary>Normal</summary> 
	    normal = 1,
		/// <summary>Escalated</summary> 
	    escalated = 2,
		/// <summary>Urgent</summary> 
	    urgent = 3
	}
	/// <summary>
	/// Identifies an action type.
	/// Indicates the type of action of a task in a work-item.
	/// </summary>
	public enum TaskActionIdentifier {
		/// <summary>assign</summary> 
	    assign,
		/// <summary>reassign</summary> 
	    reassign,
		/// <summary>complete</summary> 
	    complete,
		/// <summary>notify</summary> 
	    notify,
		/// <summary>process</summary> 
	    process,
		/// <summary>reallocate</summary> 
	    reallocate,
		/// <summary>escalate</summary> 
	    escalate,
		/// <summary>branch</summary> 
	    branch,
        /// <summary>branch and notify</summary> 
        branch_notify,
        /// <summary>pause</summary> 
        pause,
        /// <summary>none</summary> 
        none
	}
	
	/// <summary>
	/// Utility class for the workflowX namespace.
	/// <para>Contains methods that give access to the gatekeeper authentication system (eg 'Login', 'Validate')</para>
	/// </summary>
	public class x_workflow : IDisposable {
		#region Constants
		private const bool wantGatekeeper = true;
		private const string error_userget	= "Error getting user information from GateKeeper";
		private const string error_result	= "Error getting user information from GateKeeper - no result";
		private const string error_token	= "Validation error: ";
		private const string error_null		= "Authentication token is null";
		private const string error_nullid	= "User identifier is null";
		private const string error_right	= "The right has not been assigned";
		private const string error_usernone	= "No user found in GateKeeper";
		#endregion

		#region Invisible properties
		private NMCoreX gkCoreX;
		private XmlElement user;
		#endregion

		#region Visible properties
		/// <summary>An authenticated user</summary>
		/// <value>An Xml Element that describes user details</value>
		public XmlElement User {
			get { return user; }
		}
		/// <summary>The user's current token in the authentication system</summary>
		/// <value>A global unique identifier (GUID)</value>
		public string Token {
			get { return User.GetAttribute("Token"); }
		}
		/// <summary>The user's identifier in the authentication system</summary>
		/// <value>A unique integer identifier</value>
		public int UserID {
			get { return Convert.ToInt32(User.GetAttribute("UserID")); }
		}
		#endregion

		#region Constructors/Destructors
		/// <overloads>workflow constructor</overloads>
		/// <summary>Blank workflow</summary>
		public x_workflow() : base() {
			initialise();
		}
		/*
		/// <summary>Initialises the datastore connection string</summary>
		/// <param name="DSN">the dsn (from web.config)</param>
		public x_workflow(string DSN) : base(DSN) {
			initialise();
		}
		*/
		#endregion

		#region Public methods
		/// <summary>
		/// Logs a user onto the authentication system to obtain a token
		/// </summary>
		/// <param name="username">The user's username</param>
		/// <param name="password">The user's password</param>
		public void Login(string username, string password) {
			user = (XmlElement) gkCoreX.Login(username, password).DocumentElement;
			checkUser();
		}
		/// <summary>
		///	Validates that the user (identified by the token) has the required right
		///	</summary>
		public void Validate(string token, string right) {
			if (token == null || token == "")
				throw(new x_exception("error_token", String.Concat(error_token, error_null)));
			if (wantGatekeeper) {
				if (!checkPublic()) {
					user = (XmlElement) gkCoreX.ValidateService(token, right).DocumentElement;
					checkToken();
					checkRight();
				}
			} 
			/* ... compiler warning
			else {	// BlogX authentication
				if (!checkPublic(right)) {
					// add BlogX web-service access...
					checkToken(token);
					checkRight(token, right);
				}
			}
			*/
		}
		/// <overloads>Gets the user's details from the authentication system</overloads>
		/// <summary>
		/// Identifier is integer
		/// </summary>
		/// <param name="userID">The user's identifier</param>
		public XmlElement GetUser(int userID) {
			user = (XmlElement) gkCoreX.GetUser(userID).DocumentElement;
			checkUser(userID.ToString());
			return user;
		}
		/// <summary>
		/// Identifier is string
		/// </summary>
		/// <param name="agentID">The user's identifier</param>
		public XmlElement GetUser(string agentID) {
			if (agentID == null || agentID == "")
				throw(new x_exception("error_nullid", error_nullid));
			return GetUser(Convert.ToInt32(agentID));
		}
		/// <summary>
		/// Find users
		/// </summary>
		/// <param name="agentUsername">The Agent's username</param>
		/// <param name="agentCellphone">The Agent's cellphone number</param>
		public XmlElement GetUsers(string agentUsername, string agentCellphone) {
			user = (XmlElement) gkCoreX.FindUser(agentUsername, agentCellphone).DocumentElement;
			checkUser();
			if (user.SelectSingleNode("//Users/User") == null)
				throw(new x_exception("error_usernone", error_usernone));
			return user;
		}
		/// <summary>
		/// Find single user (first one if more than one)
		/// </summary>
		/// <param name="agentUsername">The Agent's username</param>
		/// <param name="agentCellphone">The Agent's cellphone number</param>
		public XmlElement GetUser(string agentUsername, string agentCellphone) {
			user = (XmlElement) gkCoreX.FindUser(agentUsername, agentCellphone).DocumentElement;
			checkUser();
			if (user.SelectSingleNode("//Users/User") == null)
				throw(new x_exception("error_usernone", error_usernone));
			return (XmlElement) user.SelectSingleNode("//Users/User");
		}
		#endregion
		
		#region Protected methods
		/// <summary>
		/// Disposes the object by implementing IDisposable.
		/// </summary>
		public void Dispose() {
			gkCoreX.Dispose();
		}
		#endregion
				
		#region Private methods
		/// <summary>
		/// Initialises the authentication system web-service proxy
		/// </summary>
		private void initialise() {
			gkCoreX = new NMCoreX();
			//gkCoreX.Credentials = System.Net.CredentialCache.DefaultCredentials;	// used when using a proxy class
		}
		/// <summary>
		/// Checks the user node returned from the authentication system for validity
		/// </summary>
		/// <exception cref="error_result">Error getting user information from GateKeeper - no result</exception>
		/// <exception cref="error_userget">Error getting user information from GateKeeper</exception>
		private void checkUser() {
			if (user == null)
				throw(new x_exception("error_userget", error_userget));
			XmlNode result = user.SelectSingleNode("Result");
			if (result == null)
				throw(new x_exception("error_result", error_result));
			string rescode = result.SelectSingleNode("ResultCode").InnerText;
			if (rescode != "0")
				throw(new x_exception("error_userget", String.Concat(error_userget, "(userid:", ") ", User.GetAttribute("UserID"), " (code:", rescode ," - '", result.SelectSingleNode("Description").InnerText, "')")));
			user.RemoveChild(result);
		}
		private void checkUser(string userid) {
			if (user == null)
				throw(new x_exception("error_userget", error_userget));
			else {
				if (user.SelectSingleNode(String.Concat("//User[@UserID='", userid, "']")) == null)
					throw(new x_exception("error_userget", String.Concat(error_userget, " (userid:", userid, ")")));
			}
			/*
			XmlNode result = user.SelectSingleNode("Result");
			if (result == null)
				throw(new x_exception("error_result", error_result));
			string rescode = result.SelectSingleNode("ResultCode").InnerText;
			if (rescode != "0")
				throw(new x_exception("error_userget", String.Concat(error_userget, " (userid:", userid ," - '", result.SelectSingleNode("Description").InnerText, "')")));
			user.RemoveChild(result);
			*/
		}
		
		/// <overloads>Checks if a right has public visibility</overloads>
		/// <summary>
		/// Used with Gatekeeper authentication
		/// </summary>
		private bool checkPublic() {
			return false;
		}
		/// <summary>
		/// Used with BlogX authentication
		/// </summary>
		private bool checkPublic(string right) {
			// add blogx logic here....
			return (right != null && right != "");
		}
		
		/// <overloads>Checks that a token is valid (exists and is not expired)</overloads>
		/// <summary>
		/// Used with Gatekeeper authentication
		/// </summary>
		/// <exception cref="x_exception">Validation error</exception>
		private void checkToken() {
			try {
				checkUser();
			} catch(x_exception x) {
				throw(new x_exception("error_token", String.Concat(error_token, x.Message)));
			}
		}
		/// <summary>
		/// Used with BlogX authentication
		/// </summary>
		/// <exception cref="x_exception">Validation error</exception>
		private void checkToken(string token) {
		}
		
		/// <overloads>Check that the user has the right</overloads>
		/// <summary>
		/// Used with Gatekeeper authentication
		/// </summary>
		/// <exception cref="x_exception">The right has not been assigned</exception>
		private void checkRight() {
			if (user == null)
				throw(new x_exception("error_userget", error_userget));
			XmlNode service = user.SelectSingleNode("Services/Service");
			if (service == null)
				throw(new x_exception("error_right", error_right));
		}
		/// <summary>
		/// Used with BlogX authentication
		/// </summary>
		/// <exception cref="x_exception">The right has not been assigned</exception>
		private void checkRight(string token, string right) {
		}
		#endregion

	}
}
